﻿/*
-----------------------------------------------------------------------------
This source file is part of Cell Cloud.

Copyright (c) 2009-2012 Cell Cloud Team - cellcloudproject@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#ifndef CellMemoryAllocatorConfig_h
#define CellMemoryAllocatorConfig_h

#include "CellMemoryAllocatedObject.h"

namespace cell
{

/** 表示内存块分配设置的分类集合。
分配类型提供了一种可配置的内存分配策略的选择方式。
它允许程序为不同的策略配置不同的内存策略，而这些配置只需要使用对应的原始类型。
*/
enum MemoryCategory
{
	/// General purpose
	MEMCATEGORY_GENERAL = 0,
	/// Adapter
	MEMCATEGORY_ADAPTER,
	/// Cellet
	MEMCATEGORY_CELLET,
	/// Storage
	MEMCATEGORY_STORAGE,
	/// Scripting
	MEMCATEGORY_SCRIPTING,

	// sentinel value, do not use 
	MEMCATEGORY_COUNT
};

} // end namespace cell

#include "CellMemorySTLAllocator.h"

#if CELL_MEMORY_ALLOCATOR == CELL_MEMORY_ALLOCATOR_NEDPOOLING

#include "CellMemoryNedPooling.h"
namespace cell
{
// 配置可选的默认分配器，这些分配器通过内存分类来进行选择。

// 配置分类。
template <MemoryCategory Cat> class CategorisedAllocPolicy : public NedPoolingPolicy{};
template <MemoryCategory Cat, size_t align = 0> class CategorisedAlignAllocPolicy : public NedPoolingAlignedPolicy<align>{};

}

#elif CELL_MEMORY_ALLOCATOR == CELL_MEMORY_ALLOCATOR_NED

#include "CellMemoryNedAlloc.h"
namespace cell
{

// configure default allocators based on the options above
// notice how we're not using the memory categories here but still roughing them out
// in your allocators you might choose to create different policies per category

// configurable category, for general malloc
// notice how we ignore the category here, you could specialise
template <MemoryCategory Cat> class CategorisedAllocPolicy : public NedAllocPolicy{};
template <MemoryCategory Cat, size_t align = 0> class CategorisedAlignAllocPolicy : public NedAlignedAllocPolicy<align>{};

}

#elif CELL_MEMORY_ALLOCATOR == CELL_MEMORY_ALLOCATOR_STD

#include "CellMemoryStdAlloc.h"
namespace cell
{

// configure default allocators based on the options above
// notice how we're not using the memory categories here but still roughing them out
// in your allocators you might choose to create different policies per category

// configurable category, for general malloc
// notice how we ignore the category here
template <MemoryCategory Cat> class CategorisedAllocPolicy : public StdAllocPolicy{};
template <MemoryCategory Cat, size_t align = 0> class CategorisedAlignAllocPolicy : public StdAlignedAllocPolicy<align>{};

}

#else

// other allocator?

#endif

namespace cell
{
// 分类别名定义。
typedef CategorisedAllocPolicy<cell::MEMCATEGORY_GENERAL> GeneralAllocPolicy;
typedef CategorisedAllocPolicy<cell::MEMCATEGORY_ADAPTER> AdapterAllocPolicy;
typedef CategorisedAllocPolicy<cell::MEMCATEGORY_CELLET> CelletAllocPolicy;
typedef CategorisedAllocPolicy<cell::MEMCATEGORY_STORAGE> StorageAllocPolicy;
typedef CategorisedAllocPolicy<cell::MEMCATEGORY_SCRIPTING> ScriptingAllocPolicy;

// 定义采用不同策略的分配器对象。
typedef AllocatedObject<GeneralAllocPolicy> GeneralAllocatedObject;
typedef AllocatedObject<AdapterAllocPolicy> AdapterAllocatedObject;
typedef AllocatedObject<CelletAllocPolicy> CelletAllocatedObject;
typedef AllocatedObject<StorageAllocPolicy> StorageAllocatedObject;
typedef AllocatedObject<ScriptingAllocPolicy> ScriptingAllocatedObject;

// 分配器类定义。
typedef GeneralAllocatedObject		GeneralAlloc;
typedef GeneralAllocatedObject		DynLibAlloc;
typedef GeneralAllocatedObject		GeneAlloc;
typedef GeneralAllocatedObject		LoggerAlloc;
typedef GeneralAllocatedObject		NucleusAlloc;
typedef GeneralAllocatedObject		ThreadAlloc;
typedef CelletAllocatedObject		CelletAlloc;
typedef AdapterAllocatedObject		AdapterAlloc;
typedef StorageAllocatedObject		StorageAlloc;

} // end namespace cell

// 实用函数
namespace cell
{
/** \addtogroup Core
 *  @{
 */
/** \addtogroup Memory
 *  @{
 */

/** 用于构建对象的数组的实用函数。
该函数不使用 new[] 进行构建。
*/
template<typename T>
T* constructN(T* basePtr, size_t count)
{
	for (size_t i = 0; i < count; ++i)
	{
		new ((void*)(basePtr+i)) T();
	}
	return basePtr;
}

/** @} */
/** @} */
} // end namespace cell

// define macros 

/** \addtogroup Core
 *  @{
 */
/** \addtogroup Memory
 *  @{
 */

#if CELL_DEBUG_MODE

/// Allocate a block of raw memory, and indicate the category of usage
#	define CELL_MALLOC(bytes, category) ::cell::CategorisedAllocPolicy<category>::allocateBytes(bytes, __FILE__, __LINE__, __FUNCTION__)
/// Allocate a block of memory for a primitive type, and indicate the category of usage
#	define CELL_ALLOC_T(T, count, category) static_cast<T*>(::cell::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))
/// Free the memory allocated with CELL_MALLOC or CELL_ALLOC_T. Category is required to be restated to ensure the matching policy is used
#	define CELL_FREE(ptr, category) ::cell::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr)

/// Allocate space for one primitive type, external type or non-virtual type with constructor parameters
#	define CELL_NEW_T(T, category) new (::cell::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T), __FILE__, __LINE__, __FUNCTION__)) T
/// Allocate a block of memory for 'count' primitive types - do not use for classes that inherit from AllocatedObject
#	define CELL_NEW_ARRAY_T(T, count, category) ::cell::constructN(static_cast<T*>(::cell::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__)), count) 
/// Free the memory allocated with CELL_NEW_T. Category is required to be restated to ensure the matching policy is used
#	define CELL_DELETE_T(ptr, T, category) if(ptr){(ptr)->~T(); ::cell::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr);}
/// Free the memory allocated with CELL_NEW_ARRAY_T. Category is required to be restated to ensure the matching policy is used, count and type to call destructor
#	define CELL_DELETE_ARRAY_T(ptr, T, count, category) if(ptr){for (size_t b = 0; b < count; ++b) { (ptr)[b].~T();} ::cell::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr);}

// aligned allocation
/// Allocate a block of raw memory aligned to SIMD boundaries, and indicate the category of usage
#	define CELL_MALLOC_SIMD(bytes, category) ::cell::CategorisedAlignAllocPolicy<category>::allocateBytes(bytes, __FILE__, __LINE__, __FUNCTION__)
/// Allocate a block of raw memory aligned to user defined boundaries, and indicate the category of usage
#	define CELL_MALLOC_ALIGN(bytes, category, align) ::cell::CategorisedAlignAllocPolicy<category, align>::allocateBytes(bytes, __FILE__, __LINE__, __FUNCTION__)
/// Allocate a block of memory for a primitive type aligned to SIMD boundaries, and indicate the category of usage
#	define CELL_ALLOC_T_SIMD(T, count, category) static_cast<T*>(::cell::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))
/// Allocate a block of memory for a primitive type aligned to user defined boundaries, and indicate the category of usage
#	define CELL_ALLOC_T_ALIGN(T, count, category, align) static_cast<T*>(::cell::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))
/// Free the memory allocated with either CELL_MALLOC_SIMD or CELL_ALLOC_T_SIMD. Category is required to be restated to ensure the matching policy is used
#	define CELL_FREE_SIMD(ptr, category) ::cell::CategorisedAlignAllocPolicy<category>::deallocateBytes(ptr)
/// Free the memory allocated with either CELL_MALLOC_ALIGN or CELL_ALLOC_T_ALIGN. Category is required to be restated to ensure the matching policy is used
#	define CELL_FREE_ALIGN(ptr, category, align) ::cell::CategorisedAlignAllocPolicy<category, align>::deallocateBytes(ptr)

/// Allocate space for one primitive type, external type or non-virtual type aligned to SIMD boundaries
#	define CELL_NEW_T_SIMD(T, category) new (::cell::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T), __FILE__, __LINE__, __FUNCTION__)) T
/// Allocate a block of memory for 'count' primitive types aligned to SIMD boundaries - do not use for classes that inherit from AllocatedObject
#	define CELL_NEW_ARRAY_T_SIMD(T, count, category) ::cell::constructN(static_cast<T*>(::cell::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__)), count) 
/// Free the memory allocated with CELL_NEW_T_SIMD. Category is required to be restated to ensure the matching policy is used
#	define CELL_DELETE_T_SIMD(ptr, T, category) if(ptr){(ptr)->~T(); ::cell::CategorisedAlignAllocPolicy<category>::deallocateBytes(ptr);}
/// Free the memory allocated with CELL_NEW_ARRAY_T_SIMD. Category is required to be restated to ensure the matching policy is used, count and type to call destructor
#	define CELL_DELETE_ARRAY_T_SIMD(ptr, T, count, category) if(ptr){for (size_t b = 0; b < count; ++b) { (ptr)[b].~T();} ::cell::CategorisedAlignAllocPolicy<category>::deallocateBytes(ptr);}
/// Allocate space for one primitive type, external type or non-virtual type aligned to user defined boundaries
#	define CELL_NEW_T_ALIGN(T, category, align) new (::cell::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T), __FILE__, __LINE__, __FUNCTION__)) T
/// Allocate a block of memory for 'count' primitive types aligned to user defined boundaries - do not use for classes that inherit from AllocatedObject
#	define CELL_NEW_ARRAY_T_ALIGN(T, count, category, align) ::cell::constructN(static_cast<T*>(::cell::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__)), count) 
/// Free the memory allocated with CELL_NEW_T_ALIGN. Category is required to be restated to ensure the matching policy is used
#	define CELL_DELETE_T_ALIGN(ptr, T, category, align) if(ptr){(ptr)->~T(); ::cell::CategorisedAlignAllocPolicy<category, align>::deallocateBytes(ptr);}
/// Free the memory allocated with CELL_NEW_ARRAY_T_ALIGN. Category is required to be restated to ensure the matching policy is used, count and type to call destructor
#	define CELL_DELETE_ARRAY_T_ALIGN(ptr, T, count, category, align) if(ptr){for (size_t _b = 0; _b < count; ++_b) { (ptr)[_b].~T();} ::cell::CategorisedAlignAllocPolicy<category, align>::deallocateBytes(ptr);}

// new / delete for classes deriving from AllocatedObject (alignment determined by per-class policy)
// Also hooks up the file/line/function params
// Can only be used with classes that derive from AllocatedObject since customised new/delete needed
#	define CELL_NEW new (__FILE__, __LINE__, __FUNCTION__)
#	define CELL_DELETE delete


#else // !CELL_DEBUG_MODE

/// Allocate a block of raw memory, and indicate the category of usage
#	define CELL_MALLOC(bytes, category) ::cell::CategorisedAllocPolicy<category>::allocateBytes(bytes)
/// Allocate a block of memory for a primitive type, and indicate the category of usage
#	define CELL_ALLOC_T(T, count, category) static_cast<T*>(::cell::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T)*(count)))
/// Free the memory allocated with CELL_MALLOC or CELL_ALLOC_T. Category is required to be restated to ensure the matching policy is used
#	define CELL_FREE(ptr, category) ::cell::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr)

/// Allocate space for one primitive type, external type or non-virtual type with constructor parameters
#	define CELL_NEW_T(T, category) new (::cell::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T))) T
/// Allocate a block of memory for 'count' primitive types - do not use for classes that inherit from AllocatedObject
#	define CELL_NEW_ARRAY_T(T, count, category) ::cell::constructN(static_cast<T*>(::cell::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T)*(count))), count) 
/// Free the memory allocated with CELL_NEW_T. Category is required to be restated to ensure the matching policy is used
#	define CELL_DELETE_T(ptr, T, category) if(ptr){(ptr)->~T(); ::cell::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr);}
/// Free the memory allocated with CELL_NEW_ARRAY_T. Category is required to be restated to ensure the matching policy is used, count and type to call destructor
#	define CELL_DELETE_ARRAY_T(ptr, T, count, category) if(ptr){for (size_t b = 0; b < count; ++b) { (ptr)[b].~T();} ::cell::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr);}

// aligned allocation
/// Allocate a block of raw memory aligned to SIMD boundaries, and indicate the category of usage
#	define CELL_MALLOC_SIMD(bytes, category) ::cell::CategorisedAlignAllocPolicy<category>::allocateBytes(bytes)
/// Allocate a block of raw memory aligned to user defined boundaries, and indicate the category of usage
#	define CELL_MALLOC_ALIGN(bytes, category, align) ::cell::CategorisedAlignAllocPolicy<category, align>::allocateBytes(bytes)
/// Allocate a block of memory for a primitive type aligned to SIMD boundaries, and indicate the category of usage
#	define CELL_ALLOC_T_SIMD(T, count, category) static_cast<T*>(::cell::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T)*(count)))
/// Allocate a block of memory for a primitive type aligned to user defined boundaries, and indicate the category of usage
#	define CELL_ALLOC_T_ALIGN(T, count, category, align) static_cast<T*>(::cell::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T)*(count)))
/// Free the memory allocated with either CELL_MALLOC_SIMD or CELL_ALLOC_T_SIMD. Category is required to be restated to ensure the matching policy is used
#	define CELL_FREE_SIMD(ptr, category) ::cell::CategorisedAlignAllocPolicy<category>::deallocateBytes((void*)ptr)
/// Free the memory allocated with either CELL_MALLOC_ALIGN or CELL_ALLOC_T_ALIGN. Category is required to be restated to ensure the matching policy is used
#	define CELL_FREE_ALIGN(ptr, category, align) ::cell::CategorisedAlignAllocPolicy<category, align>::deallocateBytes((void*)ptr)

/// Allocate space for one primitive type, external type or non-virtual type aligned to SIMD boundaries
#	define CELL_NEW_T_SIMD(T, category) new (::cell::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T))) T
/// Allocate a block of memory for 'count' primitive types aligned to SIMD boundaries - do not use for classes that inherit from AllocatedObject
#	define CELL_NEW_ARRAY_T_SIMD(T, count, category) ::cell::constructN(static_cast<T*>(::cell::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T)*(count))), count) 
/// Free the memory allocated with CELL_NEW_T_SIMD. Category is required to be restated to ensure the matching policy is used
#	define CELL_DELETE_T_SIMD(ptr, T, category) if(ptr){(ptr)->~T(); ::cell::CategorisedAlignAllocPolicy<category>::deallocateBytes((void*)ptr);}
/// Free the memory allocated with CELL_NEW_ARRAY_T_SIMD. Category is required to be restated to ensure the matching policy is used, count and type to call destructor
#	define CELL_DELETE_ARRAY_T_SIMD(ptr, T, count, category) if(ptr){for (size_t b = 0; b < count; ++b) { (ptr)[b].~T();} ::cell::CategorisedAlignAllocPolicy<category>::deallocateBytes((void*)ptr);}
/// Allocate space for one primitive type, external type or non-virtual type aligned to user defined boundaries
#	define CELL_NEW_T_ALIGN(T, category, align) new (::cell::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T))) T
/// Allocate a block of memory for 'count' primitive types aligned to user defined boundaries - do not use for classes that inherit from AllocatedObject
#	define CELL_NEW_ARRAY_T_ALIGN(T, count, category, align) ::cell::constructN(static_cast<T*>(::cell::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T)*(count))), count) 
/// Free the memory allocated with CELL_NEW_T_ALIGN. Category is required to be restated to ensure the matching policy is used
#	define CELL_DELETE_T_ALIGN(ptr, T, category, align) if(ptr){(ptr)->~T(); ::cell::CategorisedAlignAllocPolicy<category, align>::deallocateBytes((void*)ptr);}
/// Free the memory allocated with CELL_NEW_ARRAY_T_ALIGN. Category is required to be restated to ensure the matching policy is used, count and type to call destructor
#	define CELL_DELETE_ARRAY_T_ALIGN(ptr, T, count, category, align) if(ptr){for (size_t _b = 0; _b < count; ++_b) { (ptr)[_b].~T();} ::cell::CategorisedAlignAllocPolicy<category, align>::deallocateBytes((void*)ptr);}

// new / delete for classes deriving from AllocatedObject (alignment determined by per-class policy)
#	define CELL_NEW new 
#	define CELL_DELETE delete

#endif // CELL_DEBUG_MODE


namespace cell
{

/** 调用 CELL_DELETE 删除给出的指针。
@remarks
	主要用于删除外部库的指针，例如：boost 库。
*/
template<typename T>
void deletePtr(T* ptr)
{
	CELL_DELETE ptr;
}

}

/** @} */
/** @} */

#endif // CellMemoryAllocatorConfig_h
